#include "sceneobjectnavigationmap.h"
#include <standard/filewriter.h>
#include <standard/system.h>
#include "data/sceneobjectinfo.h"
#include "terrain/terrainobject.h"
#include "sceneobjectbase.h"

CSceneObjectNavigationMap::CSceneObjectNavigationMap(){
    m_ppNavigationMapInfoList = NULL;
    m_ppNavicationTextureData = NULL;
    m_nNavigCellSizeX = 0;
    m_nNavigCellSizeY = 0;
    m_fCellBlockWidth = 0.0f;
    m_fCellBlockHeight = 0.0f;
    m_fStartPosX = 0.0f;
    m_fStartPosY = 0.0f;
    m_nTextureDataType = 0;
}
CSceneObjectNavigationMap::~CSceneObjectNavigationMap(){
    DELETE2DARRAY( m_ppNavigationMapInfoList );
    DELETE2DARRAY( m_ppNavicationTextureData );
    FREE( m_pVertexData );
    FREE( m_pIndexData );
}
void CSceneObjectNavigationMap::SetSize( CTerrainObject* pTerrainObject, int32 nBlockCountX, int32 nBlockCountY, float fBlockSize, float fObjectUnitSize ){
    float _nSizeX = nBlockCountX * fBlockSize;
    float _nSizeY = nBlockCountY * fBlockSize;

    m_nNavigCellSizeX = _nSizeX / fObjectUnitSize;
    m_nNavigCellSizeY = _nSizeX / fObjectUnitSize;
    m_fCellBlockWidth = fObjectUnitSize;
    m_fCellBlockHeight = fObjectUnitSize;
    m_fStartPosX = -(_nSizeX / 2);
	m_fStartPosY = -(_nSizeY / 2);

    NEW2DARRAY( m_ppNavigationMapInfoList, SNavigationMapInfo, m_nNavigCellSizeX, m_nNavigCellSizeY );
    memset( m_ppNavigationMapInfoList[ 0 ], 0, sizeof( SNavigationMapInfo ) * m_nNavigCellSizeX * m_nNavigCellSizeY );


    NEW2DARRAY( m_ppNavicationTextureData, color32, m_nNavigCellSizeX, m_nNavigCellSizeY );
    memset( m_ppNavicationTextureData[ 0 ], 0xffffffff, sizeof( color32 ) * m_nNavigCellSizeX * m_nNavigCellSizeY );

    //
    m_pTerrainObject = pTerrainObject;
    m_nVertexDataCount = pTerrainObject->m_nCellCountX * pTerrainObject->m_nCellCountY;
    m_pVertexData = (TV3T2*)MALLOC( m_nVertexDataCount * sizeof( TV3T2 ) );
    
    m_nIndexCount = ((pTerrainObject->m_nCellCountX - 1) * (pTerrainObject->m_nCellCountY-1)) * 6;
    m_pIndexData = (uint32*)MALLOC( m_nIndexCount * sizeof(uint32) );

    float _fStartPosX = pTerrainObject->m_fStartPosX;
    float _fStartPosY = pTerrainObject->m_fStartPosY;
    int32 _nCellCountX = pTerrainObject->m_nCellCountX;
    int32 _nCellCountY = pTerrainObject->m_nCellCountY;
    float _fCellSize = pTerrainObject->m_fCellSize;
    float* _pHeightMap = pTerrainObject->m_pHeightMap;
    TV3T2* _pVertexData = m_pVertexData;
    uint32* _pIndexData = m_pIndexData;
    for( int32 i = 0, _n = 0; i < _nCellCountY; i ++ ){
        for( int32 j = 0; j < _nCellCountX; j ++ ){
            TV3T2_SETP( _pVertexData, (_fStartPosX + j * _fCellSize), *_pHeightMap, (_fStartPosY + i * _fCellSize), ((float)j / (float)(_nCellCountX - 1)), ((float)i / (float)(_nCellCountY-1)) );
            _pVertexData ++;
            _pHeightMap++;
            if( (i < _nCellCountY - 1) &&  (j < _nCellCountX - 1) ){
                _pIndexData[0] = _n;
                _pIndexData[1] = _n + _nCellCountX;
                _pIndexData[2] = _n + _nCellCountX + 1;
                _pIndexData[3] = _n + _nCellCountX + 1;
                _pIndexData[4] = _n + 1;
                _pIndexData[5] = _n;
                _pIndexData += 6;
            }
            _n ++;
        }
    }
    m_rVertexBuffer = NEW CVertexBuffer( EVT_VECTOR_TEXCOORDS, m_pVertexData, m_nVertexDataCount, True );
    m_rIndexBuffer = NEW CIndexBuffer( m_pIndexData, m_nIndexCount, False, sizeof(uint32) );

    m_rNavicationMapTextureBuffer = NEW CTextureBuffer( m_nNavigCellSizeX, m_nNavigCellSizeY, 4, m_ppNavicationTextureData[0], ClampToEdgeWrapping, ClampToEdgeWrapping, NearestFilter, NearestFilter, False );

}
void CSceneObjectNavigationMap::UpdateGeometry(){
    int32 _nCellCountX = m_pTerrainObject->m_nCellCountX;
    int32 _nCellCountY = m_pTerrainObject->m_nCellCountY;
    float* _pHeightMap = m_pTerrainObject->m_pHeightMap;
    TV3T2* _pVertexData = m_pVertexData;
    for( int32 i = 0, _n = 0; i < _nCellCountY; i ++ ){
        for( int32 j = 0; j < _nCellCountX; j ++ ){
            _pVertexData->Y = *_pHeightMap;
            _pVertexData ++;
            _pHeightMap++;
        }
    }
    m_rVertexBuffer->UpdateBuffer( m_pVertexData, m_nVertexDataCount );
}
void CSceneObjectNavigationMap::UpdateTextureData(){
    if( m_nTextureDataType == NAVIGATIONINFOCOUNT ){
        for( int32 i = 0; i < m_nNavigCellSizeY; i ++ ){
            for( int32 j = 0; j < m_nNavigCellSizeX; j ++ ){
                if( m_ppNavigationMapInfoList[ j ][ i ].m_pSO == NULL ){
                    m_ppNavicationTextureData[ j][i] = 0xffffffff;
                }else{
                    m_ppNavicationTextureData[ j][i] = 0xff0000ff;
                }
            }
        }
    }else{
        for( int32 i = 0; i < m_nNavigCellSizeY; i ++ ){
            for( int32 j = 0; j < m_nNavigCellSizeX; j ++ ){
                if( m_ppNavigationMapInfoList[ j ][ i ].m_vInfoList[ m_nTextureDataType ].m_nValue == 0 ){
                    m_ppNavicationTextureData[ j][i] = 0xffffffff;
                }else{
                    m_ppNavicationTextureData[ j][i] = m_ppNavigationMapInfoList[ j ][ i ].m_vInfoList[ m_nTextureDataType ].m_cColor;
                }
            }
        }
    }
    m_rNavicationMapTextureBuffer->Update( m_ppNavicationTextureData[0] );
}
void CSceneObjectNavigationMap::SetTextureDataType( int32 nIndex ){
    m_nTextureDataType = nIndex;
    UpdateTextureData();
}


bool32 CSceneObjectNavigationMap::WorldToCellCoords( float x, float y, int32* x_, int32* y_ ){
    x -= m_fStartPosX;
    y -= m_fStartPosY;
    int32 _nCellPosX = x / m_fCellBlockWidth;
    int32 _nCellPosY = y / m_fCellBlockHeight;
    if( _nCellPosX < 0 || _nCellPosX >= m_nNavigCellSizeX ) return False;
    if( _nCellPosY < 0 || _nCellPosY >= m_nNavigCellSizeY ) return False;
    *x_ = _nCellPosX;
    *y_ = _nCellPosY;
    return True;
}
//bool32 CSceneObjectNavigationMap::CellIsNULL( int32 x, int32 y ){
//    if( x < 0 || x >= m_nNavigCellSizeX ) return False;
//    if( y < 0 || y >= m_nNavigCellSizeY ) return False;
//    return m_ppNavigCellObjectInfo[ y ][ x ] == NULL ? True : False;
//}
CSceneObjectBase* CSceneObjectNavigationMap::GetSOInfo( int32 x, int32 y ){
    if( x < 0 || x >= m_nNavigCellSizeX ) return NULL;
    if( y < 0 || y >= m_nNavigCellSizeY ) return NULL;
    return m_ppNavigationMapInfoList[ y ][ x ].m_pSO;
}
SNavigationLayerDataInfo* CSceneObjectNavigationMap::GetInfoItem( int32 x, int32 y ){
    if( x < 0 || x >= m_nNavigCellSizeX ) return NULL;
    if( y < 0 || y >= m_nNavigCellSizeY ) return NULL;
    return m_ppNavigationMapInfoList[ y ][ x ].m_vInfoList;

}
bool32 CSceneObjectNavigationMap::CellSOListIsNULL( list<TPosition>* pCellPositionList ){
    if( pCellPositionList->empty() ) return False;
    list<TPosition>::iterator it = pCellPositionList->begin();
    list<TPosition>::iterator it_end = pCellPositionList->end();
    for( ; it != it_end; it++ ){
        TPosition& _sPos = *it;
        if( GetSOInfo( _sPos.X, _sPos.Y ) != NULL ){
            return False;
        }
    }
    return True;
}
bool32 CSceneObjectNavigationMap::SetSOInfo( int32 x, int32 y, CSceneObjectBase* pValue ){
    if( x < 0 || x >= m_nNavigCellSizeX ) return False;
    if( y < 0 || y >= m_nNavigCellSizeY ) return False;
    m_ppNavigationMapInfoList[ y ][ x ].m_pSO = pValue;
    return True;
}
bool32 CSceneObjectNavigationMap::SetSOListValue( list<TPosition>* pCellPositionList, CSceneObjectBase* pValue ){
    if( pCellPositionList->empty() ) return True;
    list<TPosition>::iterator it = pCellPositionList->begin();
    list<TPosition>::iterator it_end = pCellPositionList->end();
    for( ; it != it_end; it++ ){
        TPosition& _sPos = *it;
        SetSOInfo( _sPos.X, _sPos.Y, pValue );
    }
    return True;
}

bool32 CSceneObjectNavigationMap::CheckSOListValue( list<TPosition>* pCellPositionList, CSceneObjectBase* pValue ){
    if( pCellPositionList->empty() ) return True;
    list<TPosition>::iterator it = pCellPositionList->begin();
    list<TPosition>::iterator it_end = pCellPositionList->end();
    for( ; it != it_end; it++ ){
        TPosition& _sPos = *it;
        if( GetSOInfo( _sPos.X, _sPos.Y ) != pValue ){
            return False;
        }
    }
    return True;
}

bool32 CSceneObjectNavigationMap::CheckCanPutSOList( list<TPosition>* pCellPositionList, CSceneObjectBase* pValue ){
    if( pCellPositionList->empty() ) return True;
    list<TPosition>::iterator it = pCellPositionList->begin();
    list<TPosition>::iterator it_end = pCellPositionList->end();
    for( ; it != it_end; it++ ){
        TPosition& _sPos = *it;
        CSceneObjectBase* _pSceneObject = GetSOInfo( _sPos.X, _sPos.Y );
        if( _pSceneObject && _pSceneObject != pValue ){
            return False;
        }
    }
    return True;
}
int32 CSceneObjectNavigationMap::GetCellTypeListValue( int32 nCellType, int32 nDirType, int32 nAchorX, int32 nAchorY, list<TPosition>* pCellPostionList_ ){
    static TPosition g_vCellTypeInfo[ESDCT_COUNT][82] = {
        {{0,0},{-1000,-1000},},//ESDCT_1X1,
        {{0,0},{-1000,-1000},},//ESDCT_1X1,
        {{-1,-1},{0,-1},{1,-1},//ESDCT_3X3,
         {-1,0},{0,0},{1,0},
         {-1,1},{0,1},{1,1},
         {-1000,-1000},},
        {{-2,-2},{-1,-2},{0,-2},{1,-2},{2,-2},//ESDCT_5X5,
         {-2,-1},{-1,-1},{0,-1},{1,-1},{2,-1},
         {-2, 0},{-1, 0},{0, 0},{1, 0},{2, 0},
         {-2, 1},{-1, 1},{0, 1},{1, 1},{2, 1},
         {-2, 2},{-1, 2},{0, 2},{1, 2},{2, 2},
         {-1000,-1000},},
        {{-3,-3},{-2,-3},{-1,-3},{0,-3},{1,-3},{2,-3},{3,-3},//ESDCT_7X7,
         {-3,-2},{-2,-2},{-1,-2},{0,-2},{1,-2},{2,-2},{3,-2},
         {-3,-1},{-2,-1},{-1,-1},{0,-1},{1,-1},{2,-1},{3,-1},
         {-3, 0},{-2, 0},{-1, 0},{0, 0},{1, 0},{2, 0},{3, 0},
         {-3, 1},{-2, 1},{-1, 1},{0, 1},{1, 1},{2, 1},{3, 1},
         {-3, 2},{-2, 2},{-1, 2},{0, 2},{1, 2},{2, 2},{3, 2},
         {-3, 3},{-2, 3},{-1, 3},{0, 3},{1, 3},{2, 3},{3, 3},
         {-1000,-1000},},
        {{-4,-4},{-3,-4},{-2,-4},{-1,-4},{0,-4},{1,-4},{2,-4},{3,-4},{4,-4},//ESDCT_9X9,
         {-4,-3},{-3,-3},{-2,-3},{-1,-3},{0,-3},{1,-3},{2,-3},{3,-3},{4,-3},
         {-4,-2},{-3,-2},{-2,-2},{-1,-2},{0,-2},{1,-2},{2,-2},{3,-2},{4,-2},
         {-4,-1},{-3,-1},{-2,-1},{-1,-1},{0,-1},{1,-1},{2,-1},{3,-1},{4,-1},
         {-4, 0},{-3, 0},{-2, 0},{-1, 0},{0, 0},{1, 0},{2, 0},{3, 0},{4, 0},
         {-4, 1},{-3, 1},{-2, 1},{-1, 1},{0, 1},{1, 1},{2, 1},{3, 1},{4, 1},
         {-4, 2},{-3, 2},{-2, 2},{-1, 2},{0, 2},{1, 2},{2, 2},{3, 2},{4, 2},
         {-4, 3},{-3, 3},{-2, 3},{-1, 3},{0, 3},{1, 3},{2, 3},{3, 3},{4, 3},
         {-4, 4},{-3, 4},{-2, 4},{-1, 4},{0, 4},{1, 4},{2, 4},{3, 4},{4, 4},
         {-1000,-1000},},
    };

    TPosition* _pPosList = g_vCellTypeInfo[ nCellType ];
    while(_pPosList->X != -1000 ){
        pCellPostionList_->push_back( { nAchorX + _pPosList->X, nAchorY + _pPosList->Y } );
        _pPosList ++;
    }
    return pCellPostionList_->size();
}
bool32 CSceneObjectNavigationMap::Open( class CTerrainObject* pTerrainObject, CXML* pXML, HXMLNODEHANDLE hSceneHandle ){
    char _strBuff[64];
    HXMLNODEHANDLE _hHandle = pXML->GetNode( hSceneHandle, "navigationmap" );
    m_nNavigCellSizeX = pXML->GetAttributeValueInt32( _hHandle, "sizex" );
	m_nNavigCellSizeY = pXML->GetAttributeValueInt32( _hHandle, "sizey" );
	m_fCellBlockWidth = pXML->GetAttributeValueFloat( _hHandle, "blockx" );
	m_fCellBlockHeight = pXML->GetAttributeValueFloat( _hHandle, "blocky" );
	m_fStartPosX = pXML->GetAttributeValueFloat( _hHandle, "startx" );
	m_fStartPosY = pXML->GetAttributeValueFloat( _hHandle, "starty" );

    NEW2DARRAY( m_ppNavigationMapInfoList, SNavigationMapInfo, m_nNavigCellSizeX, m_nNavigCellSizeY );
    SNavigationMapInfo* _pNavigationMapInfo = m_ppNavigationMapInfoList[0];
    memset( _pNavigationMapInfo, 0, sizeof( SNavigationMapInfo ) * m_nNavigCellSizeX * m_nNavigCellSizeY );

    _hHandle = pXML->GetNode( _hHandle, "item" );
    while( _hHandle ){
        int32 _nIndex = pXML->GetAttributeValueInt32( _hHandle, "index" );
        int32 _nLayer = pXML->GetAttributeValueInt32( _hHandle, "layer" );
        int32 _nValue = pXML->GetAttributeValueInt32( _hHandle, "value" );
        pXML->GetAttributeValue( _hHandle, "color", _strBuff );
        color32 _cColor = HexstrToUint32( _strBuff );
        _pNavigationMapInfo[ _nIndex ].m_vInfoList[_nLayer].m_nValue = _nValue;
        _pNavigationMapInfo[ _nIndex ].m_vInfoList[_nLayer].m_cColor = _cColor;
        _hHandle = pXML->GetNextNode( _hHandle );
    }

    NEW2DARRAY( m_ppNavicationTextureData, color32, m_nNavigCellSizeX, m_nNavigCellSizeY );
    memset( m_ppNavicationTextureData[ 0 ], 0xffffffff, sizeof( color32 ) * m_nNavigCellSizeX * m_nNavigCellSizeY );

    //
    m_pTerrainObject = pTerrainObject;
    m_nVertexDataCount = pTerrainObject->m_nCellCountX * pTerrainObject->m_nCellCountY;
    m_pVertexData = (TV3T2*)MALLOC( m_nVertexDataCount * sizeof( TV3T2 ) );
    
    m_nIndexCount = ((pTerrainObject->m_nCellCountX - 1) * (pTerrainObject->m_nCellCountY-1)) * 6;
    m_pIndexData = (uint32*)MALLOC( m_nIndexCount * sizeof(uint32) );

    float _fStartPosX = pTerrainObject->m_fStartPosX;
    float _fStartPosY = pTerrainObject->m_fStartPosY;
    int32 _nCellCountX = pTerrainObject->m_nCellCountX;
    int32 _nCellCountY = pTerrainObject->m_nCellCountY;
    float _fCellSize = pTerrainObject->m_fCellSize;
    float* _pHeightMap = pTerrainObject->m_pHeightMap;
    TV3T2* _pVertexData = m_pVertexData;
    uint32* _pIndexData = m_pIndexData;
    for( int32 i = 0, _n = 0; i < _nCellCountY; i ++ ){
        for( int32 j = 0; j < _nCellCountX; j ++ ){
            TV3T2_SETP( _pVertexData, (_fStartPosX + j * _fCellSize), *_pHeightMap, (_fStartPosY + i * _fCellSize), ((float)j / (float)(_nCellCountX - 1)), ((float)i / (float)(_nCellCountY-1)) );
            _pVertexData ++;
            _pHeightMap++;
            if( (i < _nCellCountY - 1) &&  (j < _nCellCountX - 1) ){
                _pIndexData[0] = _n;
                _pIndexData[1] = _n + _nCellCountX;
                _pIndexData[2] = _n + _nCellCountX + 1;
                _pIndexData[3] = _n + _nCellCountX + 1;
                _pIndexData[4] = _n + 1;
                _pIndexData[5] = _n;
                _pIndexData += 6;
            }
            _n ++;
        }
    }
    m_rVertexBuffer = NEW CVertexBuffer( EVT_VECTOR_TEXCOORDS, m_pVertexData, m_nVertexDataCount, True );
    m_rIndexBuffer = NEW CIndexBuffer( m_pIndexData, m_nIndexCount, False, sizeof(uint32) );

    m_rNavicationMapTextureBuffer = NEW CTextureBuffer( m_nNavigCellSizeX, m_nNavigCellSizeY, 4, m_ppNavicationTextureData[0], ClampToEdgeWrapping, ClampToEdgeWrapping, NearestFilter, NearestFilter, False );
    return True;
}
void CSceneObjectNavigationMap::Save( CFileWriter* pFileWriter ){
	char _strTextBuff[ 1024 ];
	int32 _nTextLen;
	int32 i, j;
    _nTextLen = snprintf( _strTextBuff, 1024, "<navigationmap sizex=\"%d\"sizey=\"%d\"blockx=\"%f\"blocky=\"%f\"startx=\"%f\"starty=\"%f\">\n",
						  m_nNavigCellSizeX, m_nNavigCellSizeY, m_fCellBlockWidth, m_fCellBlockHeight, m_fStartPosX, m_fStartPosY );
    pFileWriter->AddText( _strTextBuff, _nTextLen );

    SNavigationMapInfo* m_pNavigationMapInfoList = m_ppNavigationMapInfoList[0];
    for( i = 0; i < m_nNavigCellSizeX * m_nNavigCellSizeY; i ++, m_pNavigationMapInfoList ++ ){
        for( j = 0; j < NAVIGATIONINFOCOUNT; j ++ ){
            if( m_pNavigationMapInfoList->m_vInfoList[j].m_nValue != 0){
                _nTextLen = snprintf( _strTextBuff, 1024, "<item index=\"%d\"layer=\"%d\"value=\"%d\"color=\"%08x\"/>\n", i, j, m_pNavigationMapInfoList->m_vInfoList[j].m_nValue, m_pNavigationMapInfoList->m_vInfoList[j].m_cColor );
                pFileWriter->AddText( _strTextBuff, _nTextLen );
            }
        }
    }

    _nTextLen = snprintf( _strTextBuff, 1024, "</navigationmap>\n" );
    pFileWriter->AddText( _strTextBuff, _nTextLen );

}